using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using AesonIdentityLibrary.DataContext;
using AesonIdentityLibrary.DataModel;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using System.Security.Claims;

namespace AesonIdentityLibrary.Repositories
{
    public class ApplicationUserManager : UserManager<ApplicationUser, int>
    {
       
        #region Ctor
        public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
            : base(store)
        {
           
        }
        #endregion

        #region create & configure
        public static ApplicationUserManager Create(SecurityDbContext ctx)
        {
            var manager = new ApplicationUserManager(new UserStore(ctx));
            Configure(manager);
            manager.PasswordValidator = (IIdentityValidator<string>)new MinimumLengthValidator(8);

            return manager;
        }

        private static ApplicationUserManager Configure(ApplicationUserManager manager)
        {
            // Configure the application user manager
            manager.UserValidator = new UserValidator<ApplicationUser,int>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };
            manager.PasswordValidator = (IIdentityValidator<string>)new MinimumLengthValidator(8);
            return manager;
        }

        public static ApplicationUserManager CreateForOwin(IdentityFactoryOptions<ApplicationUserManager> options,
                                                                                        IOwinContext context)
        {
            var manager = ApplicationUserManager.Create(context.Get<SecurityDbContext>());

            // Configure validation logic for passwords
            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = false,
                RequireDigit = true,
                RequireLowercase = true,
                RequireUppercase = true,
            };
            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser,int>(dataProtectionProvider.Create("ASP.NET Identity"));
            }
            return manager;
        }
        #endregion

        internal int ValidateClientApplication(string ApplicationTypeCode, string AppSecret)
        {
           

            using (SecurityDbContext db = new SecurityDbContext())
            {
                int i = db.ClientApplications.Count(p => p.ApplicationCode == ApplicationTypeCode
                                                            && p.ApplicationSecret == AppSecret);
                if (i != 0)
                {
                    int AppID = db.ClientApplications.First(p => p.ApplicationCode == ApplicationTypeCode
                                                            && p.ApplicationSecret == AppSecret).Id;
                    return AppID;
                }
                else
                {
                    return -1;
                }
            }
        }

        internal bool ValidateApplicationForUser(int AppID, string UserName)
        {
            using (SecurityDbContext db = new SecurityDbContext())
            {
                int i = db.UserClientAppAssignations.Count(p => p.App.Id == AppID && p.User.UserName == UserName);
                if (i == 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        internal int CheckUserSecret(string UserName, string UserSecret)
        {
            // return UserID if existe else return -1

            using (SecurityDbContext db = new SecurityDbContext())
            {
                var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
                ApplicationUser u = manager.Find(UserName, UserSecret);
                if (u != null)
                {
                    return u.Id;
                }
                else
                {
                    return 0;
                }
            }
        }

        internal ClaimsIdentity GetClaimsFromUserID(string UserID, OAuthGrantResourceOwnerCredentialsContext context)
        {
            // create identity
            ClaimsIdentity id = new ClaimsIdentity(context.Options.AuthenticationType);
            id.AddClaim(new Claim("UserName", context.UserName));
            id.AddClaim(new Claim("UserID", UserID.ToString()));
            id.AddClaim(new Claim("CurentAppTypeCode", context.ClientId));
            // Get AUthorization from database
            using (SecurityDbContext db = new SecurityDbContext())
            {
                var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
                ApplicationUser u = manager.FindById(UserID);
                foreach (var item in u.UserAuthorizationAssignation)
                {
                    // ne prendre en compte que les autorisation corespondant au type d'application que le client est en train d'utiliser
                    if (item.ClientApplication.ApplicationCode == context.ClientId)
                    {
                        id.AddClaim(new Claim("Auth", item.Authorization.Code.ToString()));
                    }
                }

            }
            return id;
        }
   

    }
}

